package com.yuncheng.spcyApi.selectXzxkApi.api;

import cn.hutool.core.io.IoUtil;
import cn.hutool.http.HttpConnection;
import cn.hutool.http.Method;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.auth0.jwt.JWT;
import com.auth0.jwt.exceptions.JWTDecodeException;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.yuncheng.exception.BusinessException;
import com.yuncheng.spcyApi.selectXzxkApi.constant.PutZwxtConstant;
import com.yuncheng.utils.RedisUtil;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Lazy;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.io.IOException;
import java.util.Date;
import java.util.List;

@Component(value = "verifyTokenApi")
public class VerifyTokenApi {

    private static final Logger log = LoggerFactory.getLogger(VerifyTokenApi.class);

    @Resource
    @Lazy
    private RedisUtil redisUtil;

    @Resource
    private PutZwxtConstant putZwxtConstant;

    /** accessTokenCacheTime//token过期时间 */
    private final long accessTokenCacheTime = 3600;

    /**
     * 用授权范围校验token 并返回用户名
     * @param access_token
     * @return
     */
    public String validAccessTokenWithScopeAndReturnUsername(String access_token) {
        String scope = PutZwxtConstant.SCOPE_ORG_LIST;
        try {
            DecodedJWT jwt = getJWT(access_token);
            if (validJwt(jwt, scope)) {
                String username = getUsername(jwt);
                String cacheUsername = getCache(access_token);
                if (StringUtils.isNotEmpty(cacheUsername) && cacheUsername.equals(username)) {
                    log.info("政务服务系统-验证token: username--{}",username);
                    return username;
                } else {
                    String serverLoginName = getServerTokenLoginName(access_token);
                    if (StringUtils.isNotBlank(serverLoginName) && serverLoginName.equals(username)) {
                        updateCache(access_token, jwt);
                        return serverLoginName;
                    }
                }
            }
        } catch (Throwable e) {
            e.printStackTrace();
            throw new BusinessException(e.getMessage());
        }

        return null;
    }

    private static DecodedJWT getJWT(String token) {
        try {
            DecodedJWT jwt = JWT.decode(token);
            return jwt;
        } catch (JWTDecodeException e) {
            return null;
        }
    }

    /**
     * 根据指定权限范围校验jwt
     * @param jwt
     * @param scope
     * @return
     */
    private boolean validJwt(DecodedJWT jwt, String scope) {
        if (jwt.getExpiresAt().getTime() > System.currentTimeMillis()) {
            List<String> scopes = getScopes(jwt);
            if (null != scopes && StringUtils.isNotEmpty(scope) && scopes.size() > 0) {
                return scopes.contains(scope);
            }
        }
        return false;
    }

    private static String getUsername(DecodedJWT jwt) {
        return jwt.getSubject();
    }

    /**
     * 根据token获取缓存的用户
     * @param access_token
     * @return
     */
    private String getCache(String access_token) {
        if (StringUtils.isEmpty(access_token)) {
            return null;
        }
        String cacheUserName = String.valueOf(redisUtil.get(PutZwxtConstant.TOKEN_PREFIX + access_token));
        if (cacheUserName != null && !cacheUserName.equals("") && !cacheUserName.equals("null")) {
            return cacheUserName;
        }
        return null;
    }

    private String getServerTokenLoginName(String access_token) throws IOException {
        if (StringUtils.isNotBlank(access_token)) {
//            String validAccessTokenUrl = "https://bg.yjj.gxzf.gov.cn/oauth/token/getloginname";
            HttpConnection connect = HttpConnection.create(putZwxtConstant.validAccessTokenUrl, null)
                    .header("Authorization", "Bearer " + access_token, true)
                    .header("Content-Type", MediaType.APPLICATION_JSON_VALUE, true)
                    .setMethod(Method.GET)
                    .setConnectTimeout(3000)
                    .connect();

            int code = connect.responseCode();
            if (200 == code) {
                String body = IoUtil.read(connect.getInputStream(), "UTF8");
                if (StringUtils.isNotBlank(body)) {
                    JSONObject result = JSON.parseObject(body);

                    log.info("政务服务系统-验证token: loginname-{}",result.get("loginname").toString());
                    return result.get("loginname").toString();
                }
            }
        }
        return null;
    }

    /**
     * 更新token对应的用户名和过期时间
     * @param access_token
     * @param jwt
     */
    private void updateCache(String access_token, DecodedJWT jwt) {
        if (StringUtils.isNotEmpty(access_token) && jwt != null) {
            redisUtil.set(PutZwxtConstant.TOKEN_PREFIX + access_token, getUsername(jwt));
            redisUtil.expire(PutZwxtConstant.TOKEN_PREFIX + access_token, getCacheTime(jwt.getExpiresAt()));
        }
    }

    /**
     * 获取token过期时间
     * @param expires
     * @return
     */
    private long getCacheTime(Date expires) {
        long result = (expires.getTime() - System.currentTimeMillis()) / 1000;
        if (result <= 0) {
            result = 1;
        }
        if (result > accessTokenCacheTime) {
            result = accessTokenCacheTime;
        }
        return result;
    }

    private static List<String> getScopes(DecodedJWT jwt) {
        return jwt.getClaim("scope").asList(String.class);
    }
}
